﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Web.UI.WebControls;
using Medianamik.Core.DAL.Repositories;
using Medianamik.Core.Interfaces;
using Medianamik.Core.Urls;
using SubSonic;
using DALS = Medianamik.Core.DAL.SubSonicDAL;

namespace Medianamik.Core.DAL
{
    internal class SubsonicConfigDALProvider : IConfigDALProvider
    {
        private readonly IDataTypeRepository _dataTypeRepository;
        private readonly IMedianamikControlRepository _medianamikControlRepository;

        public SubsonicConfigDALProvider(IDataTypeRepository dataTypeRepository, IMedianamikControlRepository medianamikControlRepository)
        {
            _dataTypeRepository = dataTypeRepository;
            _medianamikControlRepository = medianamikControlRepository;
        }

        /// <summary>
        /// Récupère la liste des MedianamikControls
        /// </summary>
        /// <returns></returns>
        [Obsolete]
        public List<MedianamikControl> GetMedianamikControls(Guid? pDataTypeId, MedianamikControlType? pControlType)
        {
            return _medianamikControlRepository.Get(pDataTypeId, pControlType).ToList();
        }
        [Obsolete]
        public MedianamikControl GetMedianamikControl(Guid pMedianamikControlID)
        {
            return _medianamikControlRepository.Get(pMedianamikControlID);
        }

        public void DeleteMedianamikControl(Guid controlId)
        {
            throw new NotImplementedException();
        }

        public MedianamikControl SaveMedianamikControl(MedianamikControl control)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<Culture> GetMedianamikCultures()
        {
            var cultures = new DALS.CultureCollection();
            cultures.Where(DALS.Culture.Columns.MedianamikActive, true);
            cultures.Load();

            return cultures.Select(c => FromDALCulture(c));
        }

        public IEnumerable<Culture> GetEditionCultures()
        {
            var cultures = new DALS.CultureCollection();
            cultures.Where(DALS.Culture.Columns.ContentManagementActive, true);
            cultures.Load();

            return cultures.Select(c => FromDALCulture(c));
        }

        public IEnumerable<Culture> GetAllCultures()
        {
            var cultures = new DALS.CultureCollection();
            cultures.Load();

            return cultures.Select(c => FromDALCulture(c));
        }

        private static Culture FromDALCulture(DALS.Culture pDalCulture)
        {
            return new Culture(pDalCulture.CultureName
                , pDalCulture.MedianamikActive ?? false
                , pDalCulture.ContentManagementActive ?? false
                , pDalCulture.Position);
        }

        public Culture SaveCulture(Culture pCulture)
        {
            var dalCulture = new DALS.Culture(pCulture.CultureInfo.Name);

            if (dalCulture.IsNew)
            {
                dalCulture.CultureName = pCulture.CultureInfo.Name;
            }
            dalCulture.ContentManagementActive = pCulture.ContentManagementActive;
            dalCulture.MedianamikActive = pCulture.MedianamikActive;
            dalCulture.Position = pCulture.Position;

            dalCulture.Save();

            return pCulture;

        }

        [Obsolete]
        public List<DataType> GetAllDataTypes()
        {
            return _dataTypeRepository.All().ToList();
        }

        [Obsolete]
        public DataType GetDataTypeById(Guid pDataTypeId)
        {
            return _dataTypeRepository.Get(pDataTypeId);
        }

        public void LogActivity(Guid? pObjectId, string pObjectName, string pUserName, string pMessage, string pIP, string pUserAgent)
        {
            LogActivity(pObjectId, pObjectName, pUserName, pMessage, pIP, pUserAgent, Logging.LogEntryType.Node);
        }
        public void LogActivity(Guid? pObjectId, string pObjectName, string pUserName, string pMessage, string pIP, string pUserAgent, Logging.LogEntryType pType)
        {
            var logItem = new DALS.ActivityLog
                              {
                                  ObjectId = pObjectId,
                                  ObjectName = pObjectName,
                                  Message = pMessage,
                                  Type = (int)pType,
                                  Ip = pIP,
                                  UserAgent = pUserAgent
                              };
            logItem.Save(pUserName);

            // TODO: Valider
            // purge des logs enregistrés il y a plus d'un an
            //DateTime target = DateTime.Now.AddYears(-1);
            //var query = new Query(DALS.ActivityLog.Schema.Name) {QueryType = QueryType.Delete};
            //query.WHERE(DALS.ActivityLog.Columns.CreatedOn, Comparison.LessOrEquals, target);
            //query.Execute();
        }

        public List<Logging.ILogEntry> GetLogEntries(int pageIndex, int count)
        {
            return GetLogEntries(pageIndex, count, null);
        }

        public List<Logging.ILogEntry> GetLogEntries(int pageIndex, int count, IDictionary<string, object> condition)
        {
            var list = new List<Logging.ILogEntry>();
            var query = MakeLogQuery(condition);
            object sortCol, sortOrd;
            if (condition.TryGetValue("SortCol", out sortCol) && condition.TryGetValue("SortOrd", out sortOrd))
            {
                string fieldName = sortCol.ToString();
                if (fieldName == "LoggedOn")
                    fieldName = "CreatedOn";
                else if (fieldName == "LoggedBy")
                    fieldName = "CreatedBy";
                query.OrderBy = sortOrd.ToString().ToUpper() == "DESC"
                              ? OrderBy.Desc(fieldName)
                              : OrderBy.Asc(fieldName);
            }
            else
            {
                query.OrderBy = OrderBy.Desc(DALS.ActivityLog.Columns.CreatedOn);
            }
            query.PageIndex = pageIndex + 1;
            query.PageSize = count;
            var collection = new DALS.ActivityLogCollection();
            collection.LoadAndCloseReader(query.ExecuteReader());
            collection.ForEach(log => list.Add(new Logging.SubSonicLogEntry(log)));
            return list;
        }

        public int CountLogEntries()
        {
            return CountLogEntries(null);
        }

        public int CountLogEntries(IDictionary<string, object> condition)
        {
            var query = MakeLogQuery(condition);
            return query.GetCount(DALS.ActivityLog.Columns.ActivityLogId);
        }

        public void PurgeLogEntries()
        {
            PurgeLogEntries(null);
        }
        public void PurgeLogEntries(IDictionary<string, object> condition)
        {
            var query = MakeLogQuery(condition);
            query.QueryType = QueryType.Delete;
            query.Execute();
        }

        private static Query MakeLogQuery(IDictionary<string, object> condition)
        {
            var query = new Query(DALS.ActivityLog.Schema.Name);

            if (condition != null)
            {
                object obj;
                if (condition.TryGetValue("CreatedOn", out obj))
                {
                    var pair = (System.Web.UI.Pair)obj;
                    if (pair.First != null && pair.Second != null)
                        query.BETWEEN_AND("CreatedOn", (DateTime)pair.First, (DateTime)pair.Second);
                    else if (pair.First != null)
                        query.WHERE("CreatedOn", Comparison.GreaterOrEquals, pair.First);
                    else if (pair.Second != null)
                        query.WHERE("CreatedOn", Comparison.LessOrEquals, pair.Second);
                }
                if (condition.TryGetValue("Message", out obj))
                {
                    var message = obj as string;
                    if (!string.IsNullOrEmpty(message))
                    {
                        query.WHERE("Message", Comparison.Like, "%" + message + "%");
                    }
                }
                if (condition.TryGetValue("Type", out obj))
                {
                    var type = (int)obj;
                    query.WHERE("Type", Comparison.Equals, type);
                }
            }

            return query;
        }

        public ILock[] GetLocksByObjectId(Guid pObjectId)
        {
            var col = new DALS.LockXCollection();
            col.Where(DALS.LockX.Columns.LockObject, pObjectId);
            col.Load();

            return col.ToArray();
        }

        public void DestroyLockByObjectId(Guid pObjectId)
        {
            Query q = DALS.LockX.Query();
            q.QueryType = QueryType.Delete;
            q.WHERE(DALS.LockX.Columns.LockObject, pObjectId);
            q.Execute();
        }

        public void DestroyLockByLockId(Guid pLockId)
        {
            Query q = DALS.LockX.Query();
            q.QueryType = QueryType.Delete;
            q.WHERE(DALS.LockX.Columns.LockId, pLockId);
            q.Execute();
        }

        public ILock CreateLock(Guid pTransacId, Guid pObjectId, TimeSpan pUltimatum, string pUserName)
        {
            var lk = new DALS.LockX
                         {
                             LockId = Guid.NewGuid(),
                             Transaction = pTransacId,
                             LockObject = pObjectId,
                             Ultimatum = (int)pUltimatum.TotalSeconds,
                             UserInfo = pUserName
                         };
            lk.Save();

            return lk;
        }

        public void UpdateLock(Guid pLockId, DateTime pActivationDate, DateTime pLastCall)
        {
            var lk = new DALS.LockX(pLockId);
            if (!lk.IsNew)
            {
                lk.ActivationDate = pActivationDate;
                lk.LastCall = pLastCall;
                lk.Save();
            }
        }

        public ILock[] GetLocks(int pPageIndex, int pPageSize)
        {
            Query q = DALS.LockX.Query();
            q.PageIndex = pPageIndex;
            q.PageSize = pPageSize;
            var col = new DALS.LockXCollection();
            using (IDataReader reader = q.ExecuteReader())
            {
                col.Load(reader);
            }
            return col.ToArray();
        }

        //public List<UrlXmlDoc> GetUrlXmlDocs()
        //{
        //    var urls = new DALS.UrlXmlDocCollection();
        //    urls.Load();

        //    return urls.Select(u => new UrlXmlDoc(u.NodeId, u.TypeId, u.ParentNodeId, u.Path, 
        //        u.CreatedOn, u.Position, u.Depth, u.LinkOnFirstChild.GetValueOrDefault(), 
        //        CultureInfo.GetCultureInfo(u.CultureName), u.Revision, u.Generation.Value, u.Xml))
        //        .ToList();
        //}

        //public List<UrlXmlDoc> GetUrlXmlDocs(Guid pNodeId)
        //{
        //    var urls = new DALS.UrlXmlDocCollection();
        //    urls.Where(DALS.UrlXmlDoc.Columns.NodeId, pNodeId);
        //    urls.Load();

        //    return urls.Select(u => new UrlXmlDoc(u.NodeId, u.TypeId, u.ParentNodeId, u.Path,
        //        u.CreatedOn, u.Position, u.Depth, u.LinkOnFirstChild.GetValueOrDefault(), CultureInfo.GetCultureInfo(u.CultureName), u.Revision, u.Generation.Value, u.Xml))
        //        .ToList();
        //}

        public List<ISchemaChange> GetSchemaChangesApplied()
        {
            var col = new DALS.SchemaChangeCollection();
            return col.Load().Select(c => FromDALSchemaChange(c)).ToList();
        }

        public void ApplySchemaChange(string pSchemaChangeSql)
        {

            var command = new QueryCommand(pSchemaChangeSql, "MedianamikDboProvider");
            DataService.ExecuteTransaction(new QueryCommandCollection { command }, "MedianamikDboProvider");
        }
        public void InsertSchemaChange(ISchemaChange pSchemaChange)
        {
            if (!pSchemaChange.DateApplied.HasValue)
            {
                throw new ArgumentException("pSchemaChange.DateApplied must have a value");
            }
            var change = new DALS.SchemaChange(DALS.SchemaChange.Columns.ScriptName, pSchemaChange.ScriptName);
            if (change.IsNew)
            {
                change.ScriptName = pSchemaChange.ScriptName;
                change.MajorReleaseNumber = pSchemaChange.MajorReleaseNumber;
                change.MinorReleaseNumber = pSchemaChange.MinorReleaseNumber;
                change.PointReleaseNumber = pSchemaChange.PointReleaseNumber;
            }
            change.DateApplied = pSchemaChange.DateApplied.Value;
            change.Save();
        }

        private static ISchemaChange FromDALSchemaChange(DALS.SchemaChange pDalChange)
        {
            return new SchemaChange
                       {
                           DateApplied = pDalChange.DateApplied,
                           MajorReleaseNumber = pDalChange.MajorReleaseNumber,
                           MinorReleaseNumber = pDalChange.MinorReleaseNumber,
                           PointReleaseNumber = pDalChange.PointReleaseNumber,
                           ScriptName = pDalChange.ScriptName
                       };
        }

        public IDictionary<String, String> GetAllConfigurations()
        {
            var configurations = new DALS.ConfigurationCollection();
            configurations.Load();

            var allConfigurations = new Dictionary<String, String>();

            configurations.ForEach(config => allConfigurations.Add(config.Key,
                config.ValueX));

            return allConfigurations;
        }

        public void SaveConfiguration(String key, string value)
        {
            var config = new DALS.Configuration(key);
            config.Key = key;
            config.ValueX = value;
            config.Save();
        }

        public void RefreshUrlDictionary()
        {
            var urlCache = new DALS.UrlCache(1);

            if (urlCache.IsNew)
                urlCache.Id = 1;

            urlCache.DateX = DateTime.Now;

            urlCache.Save();
        }
    }
}
